/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *  QuartzSurveyorPlugIn.m - iPhoneSRV console for Surveyor SRV-1 and SVS 
 *
 *  Created by Nick Kitchener.  Copyright (C) 2009  Surveyor Corporation 
 *            and Nick Kitchener.  All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details (www.gnu.org/licenses)
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* It's highly recommended to use CGL macros instead of changing the current context for plug-ins that perform OpenGL rendering */
#import <OpenGL/CGLMacro.h>
#import "QuartzSRV.h"

#import "SRVConnectOperation.h"
#import "SRVGetJPGFrameOperation.h"

#define	kQCPlugIn_Name				@"QuartzSRV"
#define	kQCPlugIn_Description		@"Quartz Surveyor SRV Controller"

@implementation QuartzSRV
@dynamic outputImageLeft, outputImageRight;

@synthesize srvIPAddress, blackfinLeftPortNumber, blackfinRightPortNumber;

/*
Here you need to declare the input / output properties as dynamic as Quartz Composer will handle their implementation
@dynamic inputFoo, outputBar;
*/

+ (NSDictionary*) attributes {
	/*
	Return a dictionary of attributes describing the plug-in (QCPlugInAttributeNameKey, QCPlugInAttributeDescriptionKey...).
	*/
	
	return [NSDictionary dictionaryWithObjectsAndKeys:kQCPlugIn_Name, QCPlugInAttributeNameKey, kQCPlugIn_Description, QCPlugInAttributeDescriptionKey, nil];
}

+ (NSDictionary*) attributesForPropertyPortWithKey:(NSString*)key {
	/*
	Specify the optional attributes for property based ports (QCPortAttributeNameKey, QCPortAttributeDefaultValueKey...).
	*/
	
	return nil;
}

+ (QCPlugInExecutionMode) executionMode {
	/*
	Return the execution mode of the plug-in: kQCPlugInExecutionModeProvider, kQCPlugInExecutionModeProcessor, or kQCPlugInExecutionModeConsumer.
	*/
	
	return kQCPlugInExecutionModeProvider;
}

+ (QCPlugInTimeMode) timeMode {
	/*
	Return the time dependency mode of the plug-in: kQCPlugInTimeModeNone, kQCPlugInTimeModeIdle or kQCPlugInTimeModeTimeBase.
	*/
	
	return kQCPlugInTimeModeNone;
}

- (id) init {
	if(self = [super init]) {
		/*
		Allocate any permanent resource required by the plug-in.
		*/
	}
	
	return self;
}

- (void) finalize {
	/*
	Release any non garbage collected resources created in -init.
	*/
	
	[super finalize];
}

- (void) dealloc {
	/* Release any resources created in -init. */
	
	[super dealloc];
}

+ (NSArray*) plugInKeys {
	/*	Return a list of the KVC keys corresponding to the internal settings of the plug-in. */
	
	return [NSArray arrayWithObjects: @"srvIPAddress", @"blackfinLeftPortNumber", @"blackfinRightPortNumber", nil];
}

- (id) serializedValueForKey:(NSString*)key; {
	/*
	Provide custom serialization for the plug-in internal settings that are not values complying to the <NSCoding> protocol.
	The return object must be nil or a PList compatible i.e. NSString, NSNumber, NSDate, NSData, NSArray or NSDictionary.
	*/
	
	return [super serializedValueForKey:key];
}

- (void) setSerializedValue:(id)serializedValue forKey:(NSString*)key {
	/*
	Provide deserialization for the plug-in internal settings that were custom serialized in -serializedValueForKey.
	Deserialize the value, then call [self setValue:value forKey:key] to set the corresponding internal setting of the plug-in instance to that deserialized value.
	*/
	
	[super setSerializedValue:serializedValue forKey:key];
}

- (QCPlugInViewController*) createViewController {
	/*
	Return a new QCPlugInViewController to edit the internal settings of this plug-in instance.
	You can return a subclass of QCPlugInViewController if necessary.
	*/
	
	return [[QCPlugInViewController alloc] initWithPlugIn:self viewNibName:@"Settings"];
}

@end

@implementation QuartzSRV (Execution)


/*
 Called by Quartz Composer when rendering of the composition starts: perform any required setup for the plug-in.
 Return NO in case of fatal failure (this will prevent rendering of the composition to start).
 */
- (BOOL) startExecution:(id<QCPlugInContext>)context {	
	NSLog(@"  IP  : %@", srvIPAddress);
	NSLog(@"  BF-L: %@", blackfinLeftPortNumber);
	NSLog(@"  BF-R: %@", blackfinRightPortNumber);
	
	leftBlackfin	= [[SRVBlackfinController alloc]init];
	rightBlackfin	= [[SRVBlackfinController alloc]init];
	
	leftBlackfin.targetURL	= @"192.168.2.10";
	leftBlackfin.portNumber = 10001;
	
	rightBlackfin.targetURL = @"192.168.2.10";
	rightBlackfin.portNumber = 10002;
	
	SRVConnectProbe *leftProbe = [[SRVConnectProbe alloc] init:leftBlackfin];
	SRVConnectProbe *rightProbe = [[SRVConnectProbe alloc] init:rightBlackfin];
	
	return YES;
}

/*
 Called by Quartz Composer when the plug-in instance starts being used by Quartz Composer.
 */
- (void) enableExecution:(id<QCPlugInContext>)context {

}

static void MyQCPlugInBufferReleaseCallback(CGLContextObj cgl_ctx, GLuint name, void* context) {
	if(context!=NULL)
		free(cgl_ctx);
}

/*
 Called by Quartz Composer whenever the plug-in instance needs to execute.
 Only read from the plug-in inputs and produce a result (by writing to the plug-in outputs or rendering to the destination OpenGL context) within that method and nowhere else.
 Return NO in case of failure during the execution (this will prevent rendering of the current frame to complete).
 
 The OpenGL context for rendering can be accessed and defined for CGL macros using:
 CGLContextObj cgl_ctx = [context CGLContextObj];
 */
- (BOOL) execute:(id<QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary*)arguments {

	if( leftProbe.bfPresent == YES ) {
	}
	
	if( rightProbe.bfPresent == YES ) {
	}
	
	SRVGetJPGFrameOperation *leftFrame =
	
	SRVGetJPGFrameOperation *rightFrame = 
	
	while( leftFrame.complete == NO ) {
		[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; // not safe - need to find a better way..
	}
	
	NSData *data= [leftFrame data];	
	NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithData:data];
	NSUInteger width  = [bitmap bytesPerRow]/4;
	NSUInteger height = [bitmap bytesPerPlane]/[bitmap bytesPerRow]; 

	unsigned char *bitmapBase = (unsigned char*) [bitmap bitmapData];
	NSUInteger bytesPerRow = [bitmap bytesPerRow];
	
	NSLog(@"width = %i, hieght = %i, bbp = %i", width, height, bytesPerRow);
	
	NSColorSpace *colourSpace = [NSColorSpace deviceRGBColorSpace];
	
	#if __BIG_ENDIAN__
	NSLog(@"big endian");
	id provider =[context
				  outputImageProviderFromBufferWithPixelFormat:QCPlugInPixelFormatARGB8
				  pixelsWide:width
				  pixelsHigh:height
				  baseAddress:(const void*)bitmapBase
				  bytesPerRow:[bitmap bytesPerRow]
				  releaseCallback:(QCPlugInBufferReleaseCallback)MyQCPlugInBufferReleaseCallback
				  releaseContext:NULL
				  colorSpace:[colourSpace CGColorSpace]
				  shouldColorMatch:YES];
	#else
	id provider =[context
				  outputImageProviderFromBufferWithPixelFormat:QCPlugInPixelFormatBGRA8
				  pixelsWide:width
				  pixelsHigh:height
				  baseAddress:(const void*)bitmapBase
				  bytesPerRow:[bitmap bytesPerRow]
				  releaseCallback:(QCPlugInBufferReleaseCallback)MyQCPlugInBufferReleaseCallback
				  releaseContext:NULL
				  colorSpace:[colourSpace CGColorSpace]
				  shouldColorMatch:NO];
	#endif
	
	[provider retain];
	
	if( provider == nil ) {
		return NO;
	}
	
	self.outputImageLeft=provider;
	[provider release];
	
	return YES;
}

/*
 Called by Quartz Composer when the plug-in instance stops being used by Quartz Composer.
 */
- (void) disableExecution:(id<QCPlugInContext>)context {
}

/*
 Called by Quartz Composer when rendering of the composition stops: perform any required cleanup for the plug-in.
 */
- (void) stopExecution:(id<QCPlugInContext>)context {	
}

@end
